package com.chenziwen.scala.chapter09

object Scala_HigherOrderFunction {
  def main(args: Array[String]): Unit = {
    // 高阶函数:函数作为一个变量传入到了另一个函数中，那么该作为参数的函数的类型是function1,即：（参数类型） => 返回类型
    // 注意：带有一个参数的函数的类型是function1，带有两个是function2，依次类推，最大参数是22个

    // 声明匿名函数
    val f1 = (s: String) => {
      println(s)
    }
    val f2 = (s: String, s1: String) => {
      println(s + s1)
    }

    println(f1)
    println(f2)
    // 调用匿名函数
    f1("aa")

    // 声明高阶函数
    def test(f: Double => Double): Double = {
      f(10)
    }

    val sum = (d: Double) => d + d
    println(test(sum))

    def test1() = () => println("......")

    val t = test1()
    t()
    test1()()

    // 高阶函数的简单写法
    def addOne(x: Int): Int = {
      x + 1
    }

    val list = List(1, 2, 3, 4)
    println(list.map(addOne))
    // 传入函数表达式
    println(list.map((x: Int) => x + 1))
    // Scala类型推断可以推断出传入参数的类型，所以参数类型可以省略
    println(list.map((x) => x + 1))
    // 单个参数可以省去括号
    println(list.map(x => x + 1))
    // 如果变量只在=>右边只出现一次，可以用_来代替
    println(list.map(_ + 1))

    // 闭包：就是一个函数把外部的那些不属于自己的对象也包含进来
    def minusxy(x: Int) = {
      def test(y: Int): Int = {
        x - y
      }

      test _
    }

    println(minusxy(10)(20))

    // 函数的科里化
    // 将函数接收多个参数转化为接收单个参数的过程，这个转化过程就叫做科里化
    def mulCurry1(x: Int, y: Int) = x * y

    def mulCurry2(x: Int) = (y: Int) => x * y

    def mulCurry3(x: Int)(y: Int) = x * y

    println(mulCurry1(10, 30))
    println(mulCurry2(10)(40))
    println(mulCurry3(10)(50))


    // 科里化的应用
    // 比较两个字符串在忽略大小写的情况下是否相等

    val str1 = "a"
    val str2 = "A"

    implicit class TestEq(str1: String) {
      def checkEq(str2: String)(f: (String, String) => Boolean): Boolean = {
        f(str1.toLowerCase, str2.toLowerCase)
      }
    }

    def compare(s1: String, s2: String): Boolean = {
      s1.equals(s2)
    }

    println(str1.checkEq(str2)(compare))
    println(str1.checkEq(str2)((x, y) => x.equals(y)))
    println(str1.checkEq(str2)(_.equals(_)))
  }
}
